#include "stdafx.h"
#include "xKernel/IxFileManager.h"
#include "xKernel/IxAttributeManager.h"
#include "Texture.h"

#define IXTEXTURE_ATTRIBUTE(name, type)              \
    ATTRIBUTE(name, type, IxTexture, Set##name)

BEGIN_ATTRIBUTE(CxTexture)
IXTEXTURE_ATTRIBUTE(File,               E_ATTRI_BSTR)
IXTEXTURE_ATTRIBUTE(DrawMode,           E_ATTRI_INT)
IXTEXTURE_ATTRIBUTE(StretchArea,        E_ATTRI_RECT)
IXTEXTURE_ATTRIBUTE(Alignment,          E_ATTRI_ALIGNMENT)
END_ATTRIBUTE

CxTexture::CxTexture()
    : m_nDrawMode(E_DRAWMODE_NORMAL)
    , m_nAlignment(E_ALIGNMENT_LEFT | E_ALIGNMENT_TOP)
    , m_rcStretch(0,0,0,0)
    , m_pBitmap(NULL)
{
    ATTRUBTES(CxTexture);
}

CxTexture::~CxTexture()
{

}

HRESULT CxTexture::GetFile(LPBSTR pbsFile)
{
    if (!pbsFile)
    {
        return E_POINTER;
    }

    *pbsFile = m_strFile.AllocSysString();

    return S_OK;
}

HRESULT CxTexture::SetFile(BSTR bsFile)
{
    m_strFile = bsFile;
    _load();
    return S_OK;
}

HRESULT CxTexture::GetDrawMode(LPINT pnMode)
{
    if (!pnMode)
    {
        return E_POINTER;
    }

    *pnMode = m_nDrawMode;

    return S_OK;
}

HRESULT CxTexture::SetDrawMode(INT nMode)
{
    m_nDrawMode = nMode;
    return S_OK;
}

HRESULT CxTexture::GetStretchArea(LPRECT lprcStretch)
{
    if (!lprcStretch)
    {
        return E_POINTER;
    }

    *lprcStretch = m_rcStretch;

    return S_OK;
}

HRESULT CxTexture::SetStretchArea(RECT rcStretch)
{
    m_rcStretch = rcStretch;
    return S_OK;
}

HRESULT CxTexture::GetAlignment(LPINT pnAlignment)
{
    if (!pnAlignment)
    {
        return E_POINTER;
    }

    *pnAlignment = m_nAlignment;

    return S_OK;
}

HRESULT CxTexture::SetAlignment(INT nAlignment)
{
    m_nAlignment = nAlignment;
    return S_OK;
}

HRESULT CxTexture::Draw(IxCanvas* pCanvas, RECT rcDest)
{
    if (m_pBitmap)
    {
        HDC hdc = NULL;
        pCanvas->GetDC(&hdc);
        Gdiplus::Graphics oGraphics(hdc);

        const Gdiplus::RectF rcDestF((Gdiplus::REAL)rcDest.left
            , (Gdiplus::REAL)rcDest.top
            , (Gdiplus::REAL)(rcDest.right - rcDest.left)
            , (Gdiplus::REAL)(rcDest.bottom - rcDest.top));

        oGraphics.DrawImage(m_pBitmap
            , rcDestF
            , 0
            , 0
            , (Gdiplus::REAL)(m_pBitmap->GetWidth())
            , (Gdiplus::REAL)(m_pBitmap->GetHeight())
            , Gdiplus::UnitPixel);

        return S_OK;
    }
    else
    {
        return E_FAIL;
    }
}

void CxTexture::_load()
{
    if (m_pBitmap)
    {
        delete m_pBitmap;
        m_pBitmap = NULL;
    }

    CComPtr<IxFileManager> spFileMgr;
    ::xCommon::GetService(__uuidof(IxFileManager), (void**)&spFileMgr);
    if (spFileMgr)
    {
        CComPtr<IxBuffer> spBuffer;
        spFileMgr->GetBuffer(CComBSTR(m_strFile), &spBuffer);
        if (spBuffer)
        {
            LPBYTE pbyBuffer = NULL;
            spBuffer->GetBuffer(&pbyBuffer);

            UINT uSize = 0;
            spBuffer->GetSize(&uSize);

            if (pbyBuffer && uSize > 0)
            {
                HGLOBAL hBuffer = ::GlobalAlloc(GMEM_MOVEABLE, uSize);
                if (hBuffer)
                {
                    void* pLockBuf = ::GlobalLock(hBuffer);
                    if (NULL != pLockBuf)
                    {
                        memcpy(pLockBuf, reinterpret_cast<void*>(pbyBuffer), uSize);
                    }
                    ::GlobalUnlock(hBuffer);

                    bool bNeedFree = true;

                    if (pLockBuf)
                    {
                        CComPtr<IStream> spStream;
                        if (S_OK == ::CreateStreamOnHGlobal(hBuffer, TRUE, &spStream) && spStream)
                        {
                            m_pBitmap = Gdiplus::Bitmap::FromStream(spStream);
                            bNeedFree = false;
                        }
                        else
                        {
                            spStream = NULL;
                        }
                    }

                    if (bNeedFree)
                    {
                        ::GlobalFree(hBuffer);
                    }
                }
            }
        }
    }
}